package com.jingdianjichi.subject.application.controller;

import com.alibaba.fastjson.JSON;
import com.google.common.base.CaseFormat;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;


import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;

/**
 * Description: 自定义注解+切面记录请求的出入参数
 * Copyright: Copyright (c) 2024
 * Create Time: 2024-08-05 17:11
 *
 * @author wanglianyun
 */
// @Aspect是Spring中AOP注解，定义切面类，加上@Aspect、@Component注解
@Aspect
@Component
public class OpLogAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(OpLogAspect.class);

    @Autowired
    HttpServletRequest request;

    // @Around 属于环绕增强，能控制切点执行前，执行后
    // @Around("@annotation(自定义注解)") 自定义注解标注在方法上，则被标注的方法执行aop方法
    @Around("@annotation(com.jingdianjichi.subject.application.controller.OpLog)")
    public Object log(ProceedingJoinPoint pjp) throws Exception {
        // 获取代理方法的信息
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        OpLog opLog = method.getAnnotation(OpLog.class);

        Object response = null;
        try {
            // 目标方法执行(也就是controller方法)
            response = pjp.proceed();
        } catch (Throwable throwable) {
            throw new Exception(throwable);
        }

        // 解析特殊参数
//        SpelExpressionParser parser = new SpelExpressionParser();
//        Expression expression = parser.parseExpression(opLog.specialParam());

        StandardEvaluationContext context = new StandardEvaluationContext();
        // 获取参数值
        Object[] args = pjp.getArgs();
        // 获取运行时参数名称
        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);

        HashMap<Object, Object> map = new HashMap<>();
        // 将参数绑定到context中
        if (parameterNames != null) {
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], args[i]);
                map.put(parameterNames[i], args[i]);
            }
        }
        // 将方法的resp当作变量放到context中，变量名称为该类名转化为小写字母开头的驼峰形式
        if (response != null) {
            context.setVariable(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, response.getClass().getSimpleName()),
                    response);
        }


        // 将特殊的参数拿出来
//        String specialParam = String.valueOf(expression.getValue(context));

        String requestParams = JSON.toJSONString(map);
        LOGGER.info("请求的操作类型为: " + opLog.opType().name() + ", 请求路径为：" + opLog.opItem() +
                "，请求参数为：" + requestParams + "，返回参数为：" + response);
        // 执行日志记录
//        handle(opLog.opType(), opLog.opItem(), params);
        return response;
    }

    private void handle(OpType opType, String opItem, String opParams) {
        LOGGER.info("请求的操作类型为: " + opType.name() + ", 请求路径为：" + opItem + "，请求参数为：" + opParams);
    }


}
